#pragma once
#include "mono/Args.h"

namespace mono
{
    struct Method
    {
        struct Desc
        {
            std::string m_Name;

            int m_NumParam;

            MonoClass *clazz;

            Desc() : m_Name(""), m_NumParam(0) {};

            bool operator<(const Desc &other) const
            {
                return std::tie(m_Name, m_NumParam) < std::tie(other.m_Name, other.m_NumParam);
            }
        } m_Desc;

        Method(const Desc &desc) : m_Desc(desc)
        {
            m_Available = Init();
        };

        Method(const Desc &desc, MonoMethod *specifiedMethod) : m_Desc(desc), method(specifiedMethod), m_Available(true)
        {
        }
        bool m_Available;

        MonoMethod *method;

        bool Init()
        {
            auto res = mono_class_get_method_from_name(m_Desc.clazz, m_Desc.m_Name.c_str(), m_Desc.m_NumParam);
            return res;
        }
        MonoObject *Invoke(Args args, MonoObject *obj = nullptr)
        {
            MonoObject *res = 0;

            void **args_ptr = (args.Empty()) ? nullptr : &args.m_Values[0];
            auto returnType = mono_runtime_invoke(method, obj, args_ptr, &res);
            ztclog::debug("return type %p result type %p", returnType, res);
            return returnType;
        };

        template <typename T>
        bool Invoke2(Args args, T &t)
        {
            auto result = Invoke(args);
            mono::Converter<T> converter;

            return converter.Decode(result, t);
        }
    };

} 
